package org.xwalk.core;

import android.util.Log;
import java.net.MalformedURLException;
import java.net.URL;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;



public class XWalkCookieManager   {

    private ArrayList<Object> constructorTypes;
    private ArrayList<Object> constructorParams;
    private ReflectMethod postWrapperMethod;


    private XWalkCoreWrapper coreWrapper;
    private Object bridge;

    protected Object getBridge() {
        return bridge;
    }


    public XWalkCookieManager() {
        constructorTypes = new ArrayList<Object>();
        constructorParams = new ArrayList<Object>();

        reflectionInit();
    }

    /**
     * Control whether cookie is enabled or disabled
     * @param accept TRUE if accept cookie
     * @since 5.0
     */
    public void setAcceptCookie(boolean accept) {
        try {
            setAcceptCookiebooleanMethod.invoke(accept);
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod setAcceptCookiebooleanMethod = new ReflectMethod(null, "setAcceptCookie");

    /**
     * Return whether cookie is enabled
     * @return TRUE if accept cookie
     * @since 5.0
     */
    public boolean acceptCookie() {
        try {
            return (Boolean)acceptCookieMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        return false;
    }

    private ReflectMethod acceptCookieMethod = new ReflectMethod(null, "acceptCookie");

    /**
     * Set cookie for a given url. The old cookie with same host/path/name will
     * be removed. The new cookie will be added if it is not expired or it does
     * not have expiration which implies it is session cookie.
     * @param url The url which cookie is set for
     * @param value The value for set-cookie: in http response header
     * @since 5.0
     */
    public void setCookie(final String url, final String value) {
        try {
            setCookieStringStringMethod.invoke(url, value);
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod setCookieStringStringMethod = new ReflectMethod(null, "setCookie");

    /**
     * Get cookie(s) for a given url so that it can be set to "cookie:" in http
     * request header.
     * @param url The url needs cookie
     * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
     * @since 5.0
     */
    public String getCookie(final String url) {
        try {
            return (String)getCookieStringMethod.invoke(url);
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        return null;
    }

    private ReflectMethod getCookieStringMethod = new ReflectMethod(null, "getCookie");

    /**
     * Remove all session cookies, which are cookies without expiration date
     * @since 5.0
     */
    public void removeSessionCookie() {
        try {
            removeSessionCookieMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod removeSessionCookieMethod = new ReflectMethod(null, "removeSessionCookie");

    /**
     * Remove all cookies
     * @since 5.0
     */
    public void removeAllCookie() {
        try {
            removeAllCookieMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod removeAllCookieMethod = new ReflectMethod(null, "removeAllCookie");

    /**
     * Get whether there are stored cookies.
     * @return true if there are stored cookies
     * @since 5.0
     */
    public boolean hasCookies() {
        try {
            return (Boolean)hasCookiesMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        return false;
    }

    private ReflectMethod hasCookiesMethod = new ReflectMethod(null, "hasCookies");

    /**
     * Remove all expired cookies
     * @since 5.0
     */
    public void removeExpiredCookie() {
        try {
            removeExpiredCookieMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod removeExpiredCookieMethod = new ReflectMethod(null, "removeExpiredCookie");

    /**
     * Flush cookies store
     * @since 5.0
     */
    public void flushCookieStore() {
        try {
            flushCookieStoreMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod flushCookieStoreMethod = new ReflectMethod(null, "flushCookieStore");

    /**
     * Get whether cookies are accepted for file scheme URLs.
     * @return true if cookies are accepted for file scheme URLs
     * @since 5.0
     */
    public boolean allowFileSchemeCookies() {
        try {
            return (Boolean)allowFileSchemeCookiesMethod.invoke();
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        return false;
    }

    private ReflectMethod allowFileSchemeCookiesMethod = new ReflectMethod(null, "allowFileSchemeCookies");

    /**
     * Sets whether cookies are accepted for file scheme URLs.
     *
     * Use of cookies with file scheme URLs is potentially insecure. Do not
     * use this feature unless you can be sure that no unintentional sharing
     * of cookie data can take place.
     * <p>
     * Note that calls to this method will have no effect if made after a
     * CookieManager instance has done any real work.
     * @param accept Whether accept cookies for file scheme URLs
     * @since 5.0
     */
    public void setAcceptFileSchemeCookies(boolean accept) {
        try {
            setAcceptFileSchemeCookiesbooleanMethod.invoke(accept);
        } catch (UnsupportedOperationException e) {
            if (coreWrapper == null) {
                throw new RuntimeException("Crosswalk's APIs are not ready yet");
            } else {
                XWalkCoreWrapper.handleRuntimeError(e);
            }
        }
        
    }

    private ReflectMethod setAcceptFileSchemeCookiesbooleanMethod = new ReflectMethod(null, "setAcceptFileSchemeCookies");


    void reflectionInit() {
        XWalkCoreWrapper.initEmbeddedMode();

        coreWrapper = XWalkCoreWrapper.getInstance();
        if (coreWrapper == null) {
            XWalkCoreWrapper.reserveReflectObject(this);
            return;
        }

        int length = constructorTypes.size();
        Class<?>[] paramTypes = new Class<?>[length+1];
        for (int i = 0; i < length; ++i) {
            Object type = constructorTypes.get(i);
            if (type instanceof String) {
                paramTypes[i] = coreWrapper.getBridgeClass((String) type);
                constructorParams.set(i, coreWrapper.getBridgeObject(constructorParams.get(i)));
            } else if (type instanceof Class<?>) {
                paramTypes[i] = (Class<?>) type;
            } else {
                assert(false);
            }
        }

        paramTypes[length] = Object.class;
        constructorParams.add(this);

        ReflectConstructor constructor = new ReflectConstructor(
                coreWrapper.getBridgeClass("XWalkCookieManagerBridge"), paramTypes);
        try {
            bridge = constructor.newInstance(constructorParams.toArray());
        } catch (UnsupportedOperationException e) {
            return;
        }

        if (postWrapperMethod != null) postWrapperMethod.invoke();

        setAcceptCookiebooleanMethod.init(bridge, null,
                "setAcceptCookieSuper", boolean.class);
        acceptCookieMethod.init(bridge, null,
                "acceptCookieSuper");
        setCookieStringStringMethod.init(bridge, null,
                "setCookieSuper", String.class, String.class);
        getCookieStringMethod.init(bridge, null,
                "getCookieSuper", String.class);
        removeSessionCookieMethod.init(bridge, null,
                "removeSessionCookieSuper");
        removeAllCookieMethod.init(bridge, null,
                "removeAllCookieSuper");
        hasCookiesMethod.init(bridge, null,
                "hasCookiesSuper");
        removeExpiredCookieMethod.init(bridge, null,
                "removeExpiredCookieSuper");
        flushCookieStoreMethod.init(bridge, null,
                "flushCookieStoreSuper");
        allowFileSchemeCookiesMethod.init(bridge, null,
                "allowFileSchemeCookiesSuper");
        setAcceptFileSchemeCookiesbooleanMethod.init(bridge, null,
                "setAcceptFileSchemeCookiesSuper", boolean.class);
    }

}
